package com.pwr.app.characteristics;

import java.text.DecimalFormat;
import java.util.ArrayList;

public class HuMomentCharacteristics implements BaseCharacteristics {

	@Override
	public double[] computeCharacteristics(boolean[][] image, int charNumber) {
		charNumber = 7;
		for (int i = 0; i < image.length; i++) {
			image[i][0] = false;
			image[i][image[i].length - 1] = false;
			image[0][i] = false;
			image[image.length - 1][i] = false;
		}

		double[] normlizeMoment = normlizeMoment(image, new double[] { 2, 0, 1, 3, 1, 2, 0 }, new double[] { 0, 2, 1, 0, 2, 1, 3 });
		double n20 = normlizeMoment[0];
		double n02 = normlizeMoment[1];
		double n11 = normlizeMoment[2];
		double n30 = normlizeMoment[3];
		double n12 = normlizeMoment[4];
		double n21 = normlizeMoment[5];
		double n03 = normlizeMoment[6];

		double[] characteristic = new double[charNumber];
		characteristic[0] = n20 + n02;
		characteristic[1] = Math.pow(n20 - n02, 2.0) + (double) 4 * Math.pow(n11, 2);
		characteristic[2] = Math.pow(n30 - (double) 3 * n12, (double) 2) + Math.pow((double) 3 * n21 - n03, (double) 2);
		characteristic[3] = Math.pow(n30 - n12, (double) 2) + Math.pow(n21 + n03, (double) 2);
		characteristic[4] = (n30 - (double) 3 * n12) * (n30 + n12) * (Math.pow(n30 + n12, (double) 2) - (double) 3 * Math.pow(n21 + n03, (double) 2)) + ((double) 3 * n21 - n03) * (n21 + n03)
				* ((double) 3 * Math.pow(n30 + n12, (double) 2) - Math.pow(n21 + n03, (double) 2));
		characteristic[5] = (n20 - n02) * (Math.pow(n30 + n12, (double) 2) - Math.pow(n21 + n03, (double) 2)) + (double) 4 * n11 * (n30 + n12) * (n21 + n03);
		characteristic[6] = ((double) 3 * n21 - n03) * (n30 + n12) * (Math.pow(n30 + n12, (double) 2) - (double) 3 * Math.pow(n21 + n03, (double) 2)) + ((double) 3 * n12 - n30) * (n21 + n03)
				* ((double) 3 * Math.pow(n30 + n12, (double) 2) - Math.pow(n21 + n03, (double) 2));
		
		return characteristic;
		
	}

	public static final long[] TENS = new long[] { 1, 10, 100, 1000, 10000, 100000 };

	public static double round(double v, int precision) {
		long t = TENS[precision]; // contains powers of ten.
		return (double) (long) (v > 0 ? v * t + 0.5 : v * t - 0.5) / t;
	}

	public double[] normlizeMoment(boolean[][] image, double[] orderP, double[] orderQ) {
		double sum = 0;
		for (int l = 0; l < image[0].length; l++)
			for (int i = 0; i < image.length; i++) {
				if (image[i][l])
					sum++;
			}
		double[] moment = centralMoment(image, orderP, orderQ);
		for (int i = 0; i < moment.length; i++)
			moment[i] = moment[i] / (Math.pow(sum, (orderP[i] + orderQ[i] + 2.0) / 2.0));
		return moment;
	}

	public double[] centralMoment(boolean[][] image, double[] orderP, double[] orderQ) {
		double[] centroid = centroid(image);
		double[] moment = new double[orderP.length];
		for (int l = 21; l < image[0].length; l++)
			for (int i = 11; i < image.length; i++)
				for (int k = 0; k < orderP.length; k++) {
					moment[k] = moment[k] + (image[i][l] ? 1 : 0) * Math.pow((double) l + 1.0 - centroid[1], orderP[k]) * Math.pow((double) l + 1.0 - centroid[0], orderQ[k]);
				}
		return moment;

	}

	private double[] centroid(boolean[][] image) {
		double sum = 0;
		for (int l = 0; l < image[0].length; l++)
			for (int i = 0; i < image.length; i++) {
				if (image[i][l])
					sum++;
			}
		double[] moment = moment(image, new double[] { 1.0, 0.0 }, new double[] { 0.0, 1.0 });
		moment[0] = moment[0] / sum;
		moment[1] = moment[1] / sum;

		return moment;
	}

	private double[] moment(boolean[][] image, double[] orderP, double[] orderQ) {
		double[] moment = new double[orderP.length];
		for (int l = 0; l < image[0].length; l++)
			for (int i = 0; i < image.length; i++)
				for (int k = 0; k < moment.length; k++) {
					moment[k] = moment[k] + (image[i][l] ? 1 : 0) * Math.pow((double) l + 1.0, orderP[k]) * Math.pow((double) i + 1.0, orderQ[k]);
				}
		return moment;
	}
}
